package com.edu.zju.scs.panacea.service.plan;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONPObject;
import com.edu.zju.scs.panacea.common.Global;
import com.edu.zju.scs.panacea.entity.BaseResult;
import com.edu.zju.scs.panacea.entity.plan.Industry;
import com.edu.zju.scs.panacea.entity.plan.Material;
import com.edu.zju.scs.panacea.entity.plan.Plan;
import com.edu.zju.scs.panacea.entity.plan.Task;
import com.edu.zju.scs.panacea.entity.query.MaterialQuery;
import com.edu.zju.scs.panacea.entity.query.PlanQuery;
import com.edu.zju.scs.panacea.entity.vo.AvalibleLocsVO;
import com.edu.zju.scs.panacea.entity.vo.DataShowVO;
import com.edu.zju.scs.panacea.entity.vo.MaterialAuditResultVO;
import com.edu.zju.scs.panacea.entity.vo.PlanVO;
import com.edu.zju.scs.panacea.mapper.plan.IndustryMapper;
import com.edu.zju.scs.panacea.mapper.plan.MaterialMapper;
import com.edu.zju.scs.panacea.mapper.plan.PlanMapper;
import com.edu.zju.scs.panacea.mapper.plan.TaskMapper;
import com.edu.zju.scs.panacea.mapper.resource.TemplateRelLocMapper;
import com.edu.zju.scs.panacea.service.resource.PackageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: Yue Liang
 * @Date: 2019-01-03 21:02
 */
@Service
public class PlanService {

    @Autowired
    private PlanMapper planMapper;

    @Autowired
    private IndustryMapper industryMapper;

    @Autowired
    private PackageService packageService;

    @Autowired
    private TaskMapper taskMapper;

    @Autowired
    private TemplateRelLocMapper templateRelLocMapper;

    @Autowired
    private MaterialMapper materialMapper;

    /**
     * 根据ID查询某个计划信息
     * @param id
     * @return
     */
    public BaseResult getPlan(Long id) {
        BaseResult baseResult = new BaseResult();
        Plan plan = planMapper.selectPlan(id);
        PlanVO planVO = new PlanVO();
        // 计划ID
        planVO.setId(plan.getId());
        // 计划名称
        planVO.setName(plan.getName());
        // 计划所属行业ID和名称
        planVO.setIndustryId(plan.getIndustryId());
        Industry industry = industryMapper.selectIndustry(plan.getIndustryId());
        planVO.setIndustryName(industry.getName());
        // 广告类型
        planVO.setType(plan.getType());
        // 开始和结束日期
        planVO.setStartDate(plan.getStartDate());
        planVO.setEndDate(plan.getEndDate());
        // 计算计划包含的有效资源位有多少个
        planVO.setLocsNum(getAvailableLocsNum(plan));

        if (plan == null) {
            baseResult.error("无此id对应的计划");
        } else {
            baseResult.success(planVO);
        }
        return baseResult;
    }

    /**
     * 查询所有行业信息
     * @return
     */
    public BaseResult getPlanBySeller(PlanQuery planQuery) {
        BaseResult baseResult = new BaseResult();
        List<Plan> planList = planMapper.selectSpecificPlans(planQuery);
        List<PlanVO> planVOList = new ArrayList<>();
        for (Plan plan : planList) {
            PlanVO planVO = new PlanVO();
            // 计划ID
            planVO.setId(plan.getId());
            // 计划名称
            planVO.setName(plan.getName());
            // 计划所属行业ID和名称
            planVO.setIndustryId(plan.getIndustryId());
            Industry industry = industryMapper.selectIndustry(plan.getIndustryId());
            planVO.setIndustryName(industry.getName());
            // 广告类型
            planVO.setType(plan.getType());
            // 开始和结束日期
            planVO.setStartDate(plan.getStartDate());
            planVO.setEndDate(plan.getEndDate());
            // 计算计划包含的有效资源位有多少个
            planVO.setLocsNum(getAvailableLocsNum(plan));
            // 计划状态
            planVO.setState(plan.getState());
            planVOList.add(planVO);
        }
        if (planList == null) {
            baseResult.error("查询计划信息失败");
        } else {
            baseResult.success(planVOList);
        }
        return baseResult;
    }


    public BaseResult deletePlan(Long id) {
        BaseResult baseResult = new BaseResult();
        long deleteDevNums = planMapper.deletePlan(id);
        // 找到计划下的所有任务，并删除绑定的素材
        List<Long> taskList = taskMapper.selectTasksByPlan(id);
        for (Long taskId : taskList) {
            materialMapper.deleteMaterialByTask(taskId);
        }
        // 删除计划下的任务
        taskMapper.deleteTaskByPlan(id);
        if (deleteDevNums == 0) {
            baseResult.error("删除计划失败！");
        } else {
            baseResult.success(deleteDevNums);
        }
        return baseResult;
    }

    public BaseResult addPlan(Plan plan, List<Long> templateIds, List<String> materialUrls, List<Integer> materialSeconds) {
        BaseResult baseResult = new BaseResult();
        // 返回插入记录条数
        Long insertNums = planMapper.insertPlan(plan);
        // 计划分解为任务, 每个资源位对应一个任务
        Set<Long> locs = getAvailableLocs(plan);
        for (Long locId : locs) {
            Task task = new Task();
            task.setLocId(locId);
            task.setPlanId(plan.getId());
            task.setStartDate(plan.getStartDate());
            task.setEndDate(plan.getEndDate());
            task.setState(plan.getState());
            task.setBinLaunchTime(turnTimeSlotToBin(plan.getLaunchTime()));
            taskMapper.insertTask(task);
            // 每个任务对应一个素材
            Material material = new Material();
            material.setTaskId(task.getId());
            // 找到其中该资源位对应的模板和素材的序号
            int index = getPlanTemplateIdByLoc(locId, templateIds);
            if (index == -1) {
                // todo throw exception
            }
            material.setTemplateId(templateIds.get(index));
            material.setUrl(materialUrls.get(index));
            material.setSeconds(materialSeconds.get(index));
            material.setType(plan.getType());
            materialMapper.insertMaterial(material);
        }

        if (insertNums == null) {
            baseResult.error("新增计划失败！");
        } else {
            baseResult.success(insertNums);
        }
        return baseResult;
    }

    public BaseResult editPlan(Plan plan) {
         BaseResult baseResult = new BaseResult();
        // 返回更新的记录条数
        Long updateNums = planMapper.updatePlan(plan);
        if (updateNums == null) {
            baseResult.error("更新计划失败！");
        } else {
            baseResult.success(updateNums);
        }
        return baseResult;
    }

    // 当一个素材被审核时，判断该素材所属的计划是否否被审核，
    // 如果素材都被审核，均成功，则该计划审核成功
    // 如果其中有素材审核失败，则计划失败
    public void auditPlan(Long materialId) {

        Long planId = planMapper.selectPlanIdByMaterial(materialId);
        MaterialQuery materialQuery = new MaterialQuery();
        materialQuery.setPlanId(planId);
        List<Material> materials = materialMapper.selectSpecificMaterials(materialQuery);
        boolean allCompleted = true;
        boolean planSuccess = true;
        String planFailReason = "";
        for (Material material : materials) {
            if (material.getState() == 0) {
                allCompleted = false;
                break;
            }

            if (material.getState() == 2) {
                planSuccess = false;
                planFailReason = planFailReason + material.getId() + ":" + material.getRemark() + ";";
            }
        }

        if (allCompleted && planSuccess) {
            planMapper.passPlan(planId);
        }

        if (allCompleted && !planSuccess) {
            planMapper.rejectPlan(planId, planFailReason);
        }

    }

    public BaseResult getAuditResult(Long id) {
        BaseResult baseResult = new BaseResult();
        MaterialQuery materialQuery = new MaterialQuery();
        materialQuery.setPlanId(id);
        List<Material> materials = materialMapper.selectSpecificMaterials(materialQuery);
        Plan plan = planMapper.selectPlan(id);
        List<MaterialAuditResultVO> materialAuditResultVOS = new ArrayList<>();
        for (Material material : materials) {
            if (material.getState() == 2) {
                MaterialAuditResultVO materialAuditResultVO = new MaterialAuditResultVO();
                materialAuditResultVO.setMaterialId(material.getId());
                materialAuditResultVO.setUrl(material.getUrl());
                materialAuditResultVO.setType(plan.getType());
                materialAuditResultVO.setRemark(material.getRemark() == null ? "未说明原因" : material.getRemark());
                materialAuditResultVOS.add(materialAuditResultVO);
            }
        }
        baseResult.success(materialAuditResultVOS);
        return baseResult;
    }


    private Set<Long> getAvailableLocs(Plan plan) {
        List<Long> packageIdsLong = plan.getPackageIds().stream().map(Long::parseLong).collect(Collectors.toList());
        List<Long> locIdsLong = plan.getLocIds().stream().map(Long::parseLong).collect(Collectors.toList());
        BaseResult locsResult = packageService.getAvalibleLocs(packageIdsLong, locIdsLong, plan.getType());
        if (locsResult.getCode() == Global.Code.success) {
            AvalibleLocsVO avalibleLocsVO = (AvalibleLocsVO) locsResult.getObject();
            return avalibleLocsVO.getLocs();
        } else {
            return new HashSet<>();
        }
    }

    private Integer getAvailableLocsNum(Plan plan) {
        List<Long> packageIdsLong = plan.getPackageIds().stream().map(Long::parseLong).collect(Collectors.toList());
        List<Long> locIdsLong = plan.getLocIds().stream().map(Long::parseLong).collect(Collectors.toList());
        BaseResult locsResult = packageService.getAvalibleLocs(packageIdsLong, locIdsLong, plan.getType());
        if (locsResult.getCode() == Global.Code.success) {
            AvalibleLocsVO avalibleLocsVO = (AvalibleLocsVO) locsResult.getObject();
            return avalibleLocsVO.getNum();
        } else {
            return 0;
        }
    }

    private String turnTimeSlotToBin(List<Integer> launchTimeList) {
        String launchTime = "";
        for (int i = 0; i < 24; i++) {
            if (launchTimeList.contains(i)) {
                launchTime += "1";
            } else {
                launchTime += "0";
            }
        }
        return launchTime;
    }

    private Integer getPlanTemplateIdByLoc(Long locId, List<Long> templates) {
        List<Long> templateIdsBelongLoc = templateRelLocMapper.selectTemplatesByLoc(locId);
        for (int i = 0; i < templates.size(); i++) {
            if (templateIdsBelongLoc.contains(templates.get(i))) {
                return i;
            }
        }
        return -1;
    }
}

